#include "processor.h"

Processor::Processor()
{
}
//-----------------------------------------------------------
void Processor::Print(String string)
{
    LogManager::getSingleton().MessageM(string);
}
void Processor::Print(int X)
{
    LogManager::getSingleton().MessageM(LogManager::getSingleton().toStr(X));
}
void Processor::Print(Byte byte)
{
    LogManager::getSingleton().MessageM(LogManager::getSingleton().toStr(byte));
}
void Processor::Print(DByte dByte)
{
    LogManager::getSingleton().MessageM(LogManager::getSingleton().toStr(dByte[0]));
    LogManager::getSingleton().MessageM(LogManager::getSingleton().toStr(dByte[1]));
}
void Processor::Print(Word word)
{
    LogManager::getSingleton().MessageM(LogManager::getSingleton().toStr(word[0]));
    LogManager::getSingleton().MessageM(LogManager::getSingleton().toStr(word[1]));
    LogManager::getSingleton().MessageM(LogManager::getSingleton().toStr(word[2]));
    LogManager::getSingleton().MessageM(LogManager::getSingleton().toStr(word[3]));
}
void Processor::Print(DWORD dword)
{
    LogManager::getSingleton().MessageM(LogManager::getSingleton().toStr(dword));
}

void Processor::Print()
{
    LogManager::getSingleton().MessageE();
}

Byte toChar(Byte hex)
{
    if(hex <= 0x09)
    {
        return hex + _ANSII_NUM;
    }
    else if(0x0A <= hex && hex <= 0x0F)
    {
        return hex + _ANSII_LET;
    }

    return 0x7E;
}
Byte toHex(Byte ansii)
{
    if(ansii >= 0x30 && ansii <= 0x39)
    {
        return ansii - _ANSII_NUM;
    }
    else if(ansii >= 0x41 && ansii <= 0x46)
    {
        return ansii - _ANSII_LET;
    }

    return 0x5E;
}
DByte toChar(DByte hex)
{
    DByte temp;
    temp[0] = toChar(hex[0]);
    temp[1] = toChar(hex[1]);

    return temp;
}
DByte toHex(DByte ansii)
{
    DByte temp;
    temp[0] = toHex(ansii[0]);
    temp[1] = toHex(ansii[1]);

    return temp;
}
Word toChar(Word hex)
{
    Word temp;
    temp[0] = toChar(hex[0]);
    temp[1] = toChar(hex[1]);
    temp[2] = toChar(hex[2]);
    temp[3] = toChar(hex[3]);
    return temp;
}
Word toHex(Word ansii)
{
    Word temp;
    temp[0] = toHex(ansii[0]);
    temp[1] = toHex(ansii[1]);
    temp[2] = toHex(ansii[2]);
    temp[3] = toHex(ansii[3]);

    return temp;
}

Word DWORDtoWord(DWORD from)
{
    Word to;
    to[0] = (from >> 24) & 0xff;
    to[1] = (from >> 16) & 0xff;
    to[2] = (from >> 8) & 0xff;
    to[3] = from & 0xff ;

    return to;
}
DByte IntToDByte(int from)
{
    DByte ret;

    ret[0] = (from >> 8) & 0xFF;
    ret[1] = from & 0xFF;

    return ret;
}
int DByteToInt(DByte from)
{
    return from[0]*BLOCK_SIZE + from[1];
}
//-----------------------------------------------------------
Word Processor::ReadMem(int address)
{
    Byte x, y;
    x = address / BLOCK_SIZE;
    y = address % BLOCK_SIZE;

    int pagefile = (int)(PL[0])*BLOCK_SIZE + x;
    int pagefileElement = ((*memory)[pagefile])[3];
    int realAddress = pagefileElement*BLOCK_SIZE+y;

    //qDebug() << "block:" << x << " word:" << y << "pagefile: " << pagefile << " pagefileElement:" << pagefileElement << " realAddress:" << realAddress;

    return ((*memory)[realAddress]);
}
void Processor::WriteMem(int address, Word w)
{
    int x, y;
    x = address / BLOCK_SIZE;
    y = address % BLOCK_SIZE;

    int pagefile = (int)(PL[0])*BLOCK_SIZE + x;
    int pagefileElement = ((*memory)[pagefile])[3];
    int realAddress = pagefileElement*BLOCK_SIZE+y;

    //qDebug() << "block:" << x << " word:" << y << "pagefile: " << (int)pagefile << " pagefileElement:" << (int)pagefileElement << " realAddress:" << realAddress;

    (*memory)[realAddress] = w;
}

Word Processor::ReadMem(Byte x, Byte y)
{
    int pagefile = (int)(PL[0])*BLOCK_SIZE + x;
    int pagefileElement = ((*memory)[pagefile])[3];
    int realAddress = pagefileElement*BLOCK_SIZE+y;

    //qDebug() << "block:" << x << " word:" << y << "pagefile: " << pagefile << " pagefileElement:" << pagefileElement << " realAddress:" << realAddress;

    return ((*memory)[realAddress]);
}
void Processor::WriteMem(Byte x, Byte y, Word w)
{
    int pagefile = (int)(PL[0])*BLOCK_SIZE + x;
    int pagefileElement = ((*memory)[pagefile])[3];
    int realAddress = pagefileElement*BLOCK_SIZE+y;

    //qDebug() << "block:" << x << " word:" << y << "pagefile: " << pagefile << " pagefileElement:" << pagefileElement << " realAddress:" << realAddress;

    (*memory)[realAddress] = w;
}

void Processor::Run()
{
    int address = PS[0]*BLOCK_SIZE + PS[1];

    Word command = ReadMem(address);
    address++;
    PS[0] = address / BLOCK_SIZE;
    PS[1] = address % BLOCK_SIZE;

    Print("> ");
    Print(command);
    Print(" -> ");

    switch (command[0])
    {
    case 'A':
        {
            ADDA();
        }break;
    case 'C':
        {
            switch (command[1])
            {
            case 'H':
                {
                    CHAN();
                }break;
            case 'M':
                {
                    CMPA();
                }break;
            default:
                {
                    Print("Unidentified command:");
                    Print(command);
                    Print();
                    PPR = 0x02;
                }break;
            }
        }break;
    case 'D':
        {
            switch (command[1])
            {
            case 'A':
                {
                    DA(command[2], command[3]);
                }break;
            case 'B':
                {
                    DB(command[2], command[3]);
                }break;
            case 'E':
                {
                    Print("Unidentified command:");
                    Print("HERP");
                    Print();
                }break;
            case 'I':
                {
                    DByte z;
                    z[0] = command[2];
                    z[1] = command[3];
                    DI(z);
                }break;
            default:
                {
                    Print("Unidentified command:");
                    Print(command);
                    Print();
                    PPR = 0x02;
                }break;
            }
        }break;
    case 'H':
        {
            HALT();
            return;
        }break;
    case 'J':
        {
            switch (command[1])
            {
            case 'E':
                {
                    DByte q;
                    q[0] = command[2];
                    q[1] = command[3];
                    JE(q);
                }break;
            case 'G':
                {
                    DByte q;
                    q[0] = command[2];
                    q[1] = command[3];
                    JG(q);
                }break;
            case 'L':
                {
                    DByte q;
                    q[0] = command[2];
                    q[1] = command[3];
                    JL(q);
                }break;
            case 'P':
                {
                    DByte q;
                    q[0] = command[2];
                    q[1] = command[3];
                    JP(q);
                }break;
            default:
                {
                    Print("Unidentified command:");
                    Print(command);
                    Print();
                    PPR = 0x02;
                }break;
            }
        }break;
    case 'L':
        {
            switch (command[1])
            {
            case 'A':
                {
                    LA(command[2], command[3]);
                }break;
            case 'B':
                {
                    LB(command[2], command[3]);
                }break;
            case 'C':
                {
                    LCK(command[3]);
                }break;
            default:
                {
                    Print("Unidentified command:");
                    Print(command);
                    Print();
                    PPR = 0x02;
                }break;
            }
        }break;
    case 'M':
        {
            MULT();
        }break;
    case 'R':
        {
            switch (command[1])
            {
            case 'D':
                {
                    RDM(command);
                }break;
            case 'E':
                {
                    READ(command);
                }break;
            default:
                {
                    Print("Unidentified command:");
                    Print(command);
                    Print();
                    PPR = 0x02;
                }break;
            }
        }break;
    case 'S':
        {
            switch (command[1])
            {
            case 'A':
                {
                    SA(command[2], command[3]);
                }break;
            case 'B':
                {
                    SB(command[2], command[3]);
                }break;
            case 'U':
                {
                    SUBA();
                }break;
            default:
                {
                    Print("Unidentified command:");
                    Print(command);
                    Print();
                    PPR = 0x02;
                }break;
            }
        }break;
    case 'U':
        {
            switch (command[1])
            {
            case 'A':
                {
                    UA(command[2], command[3]);
                }break;
            case 'B':
                {
                    UB(command[2], command[3]);
                }break;
            case 'N':
                {
                    UNL(command[3]);
                }break;
            default:
                {
                    Print("Unidentified command:");
                    Print(command);
                    Print();
                    PPR = 0x02;
                }break;
            }
        }break;
    case 'W':
        {
            switch (command[1])
            {
            case 'R':
                {
                    WRIT(command);
                }break;
            case 'T':
                {
                    WTM(command);
                }break;
            default:
                {
                    Print("Unidentified command:");
                    Print(command);
                    Print();
                    PPR = 0x02;
                }break;
            }
        }break;
    default:
        {
            Print("Unidentified command:");
            Print(command);
            Print();
            PPR = 0x02;
        }break;
    }
}
//VIRTUAL MACHINE COMMANDS:
void Processor::HALT(void)
{
    Print("F:");
    Print("Program halted.");
    Print();

    PPR = 0x05;
    MODE = 0x01;
}
void Processor::LA(Byte x, Byte y)
{
    Print("F:");
    Print("LA");
    Print(x);
    Print(y);
    Print();
    RA = ReadMem(toHex(x), toHex(y));
}

void Processor::LB(Byte x, Byte y)
{
    Print("F:");
    Print("LB");
    Print(x);
    Print(y);
    Print();
    RB = ReadMem(toHex(x), toHex(y));

}

void Processor::SA(Byte x, Byte y)
{
    Print("F:");
    Print("SA");
    Print(x);
    Print(y);
    Print();
    WriteMem(toHex(x), toHex(y), RA);
}

void Processor::SB(Byte x, Byte y)
{
    Print("F:");
    Print("SB");
    Print(x);
    Print(y);
    Print();
    WriteMem(toHex(x), toHex(y), RB);
}

void Processor::CHAN(void)
{
    Print("F:");
    Print("CHAN");
    Print();
    Word temp = RA;
    RA = RB;
    RB = temp;
}


void Processor::LCK(Byte x)
{
    Print("F:");
    Print("LCK");
    Print(x);
    Print();
    SPR [0] = toHex(x);
    SPR [1] = 2;

    WORD bitmask = 1 << toHex(x);
    WORD sr;
    sr = MAKEWORD(SR[1], SR[0]);
    bool isLocked = (sr & bitmask) ? 1 : 0;
    if(isLocked)
    {
        MODE = 0x01;
        Print("Block ");
        Print(toHex(x));
        Print(" is already locked.");
        Print();
        PPR  = 6;
    }
    else
    {
        sr = sr ^ bitmask;
        SR[0] = (sr >> 8) & 0xff;
        SR[1] = sr & 0xff;
        SPR [0] = 0x00;
        SPR [1] = 0x00;
    }
}
void Processor::UA(Byte x, Byte y)
{
    Print("F:");
    Print("UA");
    Print(x);
    Print(y);
    Print();

    WORD bitmask = 1 << toHex(x);
    WORD sr;
    sr = MAKEWORD(SR[1], SR[0]);
    bool isLocked = (sr & bitmask) ? 1 : 0;
    if (!(isLocked))
    {
        MODE = 0x01;
        PPR  = 6;
    }
    else
    {
        int realAddress = (BAR[0]+toHex(x))*BLOCK_SIZE + toHex(y);
        RA = (*memory)[realAddress];
    }
}
void Processor::UB(Byte x, Byte y)
{
    Print("F:");
    Print("UB");
    Print(x);
    Print(y);
    Print();

    WORD bitmask = 1 << toHex(x);
    WORD sr;
    sr = MAKEWORD(SR[1], SR[0]);
    bool isLocked = (sr & bitmask) ? 1 : 0;
    if (!(isLocked))
    {
        MODE = 0x01;
        PPR  = 6;
    }
    else
    {
        int realAddress = (BAR[0]+toHex(x))*BLOCK_SIZE + toHex(y);
        RB = (*memory)[realAddress];
    }
}
void Processor::DA(Byte x, Byte y)
{
    Print("F:");
    Print("DA");
    Print(x);
    Print(y);
    Print();

    WORD bitmask = 1 << toHex(x);
    WORD sr;
    sr = MAKEWORD(SR[1], SR[0]);
    bool isLocked = (sr & bitmask) ? 1 : 0;
    if (!(isLocked))
    {
        MODE = 0x01;
        Print("Block ");
        Print(toHex(x));
        Print(" is already locked.");
        Print();
        PPR  = 6;
    }
    else
    {
        int realAddress = (BAR[0]+toHex(x))*BLOCK_SIZE + toHex(y);
        (*memory)[realAddress] = RA;
    }
}
void Processor::DB(Byte x, Byte y)
{
    Print("F:");
    Print("DB");
    Print(x);
    Print(y);
    Print();

    WORD bitmask = 1 << toHex(x);
    WORD sr;
    sr = MAKEWORD(SR[1], SR[0]);
    bool isLocked = (sr & bitmask) ? 1 : 0;
    if (!(isLocked))
    {
        MODE = 0x01;
        Print("Block ");
        Print(toHex(x));
        Print(" is already locked.");
        Print();
        PPR  = 6;
    }
    else
    {
        int realAddress = (BAR[0]+toHex(x))*BLOCK_SIZE + toHex(y);
        (*memory)[realAddress] = RB;
    }

}
void Processor::UNL(Byte x)
{
    Print("F:");
    Print("UNL");
    Print(x);
    Print();
    SPR [0] = toHex(x);
    SPR [1] = 2;

    WORD bitmask = 1 << toHex(x);
    WORD sr;
    sr = MAKEWORD(SR[1], SR[0]);
    bool isLocked = (sr & bitmask) ? 1 : 0;
    if(isLocked)
    {
        bitmask = ~bitmask;
        sr = sr & bitmask;
        SR[0] = (sr >> 8) & 0xff;
        SR[1] = sr & 0xff;
        SPR [0] = 0x00;
        SPR [1] = 0x00;
    }
    else
    {
        MODE = 0x01;
        Print("Block ");
        Print(toHex(x));
        Print(" is already locked.");
        Print();
        PPR  = 6;
    }
}

void Processor::ADDA(void)
{
    Print("F:");
    Print("ADDA");
    Print();

    DWORD tempA = MAKELONG(MAKEWORD(RA[3], RA[2]), MAKEWORD(RA[1], RA[0]));

    DWORD tempB = MAKELONG(MAKEWORD(RB[3], RB[2]), MAKEWORD(RB[1], RB[0]));

    tempA += tempB;

    RA = DWORDtoWord(tempA);
}
void Processor::SUBA(void)
{
    Print("F:");
    Print("SUBA");
    Print();

    DWORD tempA = MAKELONG(MAKEWORD(RA[3], RA[2]), MAKEWORD(RA[1], RA[0]));

    DWORD tempB = MAKELONG(MAKEWORD(RB[3], RB[2]), MAKEWORD(RB[1], RB[0]));

    if(tempA < tempB)
    {
        SF = 2;
    }
    else if(tempA == tempB)
    {
        SF = 0;
    }
    else
    {
        SF = 1;
    }

    tempA -= tempB;

    RA = DWORDtoWord(tempA);
}
void Processor::MULT(void)
{
 Print("F:");
 Print("MULT");
 Print();

    DWORD ra = MAKELONG(MAKEWORD(RA[3], RA[2]), MAKEWORD(RA[1], RA[0]));
    DWORD rb = MAKELONG(MAKEWORD(RB[3], RB[2]), MAKEWORD(RB[1], RB[0]));


    long long mult= ra;
    mult=mult*rb;


    DWORD upper = mult >> 32;
    DWORD lower = mult & 0x00000000FFFFFFFF;
    Word temp;
    temp[0] = (upper >> 24) & 0xff;
    temp[1] = (upper >> 16) & 0xff;
    temp[2] = (upper >> 8) & 0xff;
    temp[3] = upper & 0xff ;

    if(temp[0] == 0x00 && temp[1] == 0x00 && temp[2] == 0x00 && temp[3] == 0x00)
    {
        SF = 0;
    }
    else
    {
        SF = 3;
        RA[0] = temp[0];
        RA[1] = temp[1];
        RA[2] = temp[2];
        RA[3] = temp[3];


            }
    temp[0] = (lower >> 24) & 0xff;
    temp[1] = (lower >> 16) & 0xff;
    temp[2] = (lower >> 8) & 0xff;
    temp[3] = lower & 0xff ;

    RB[0] = temp[0];
    RB[1] = temp[1];
    RB[2] = temp[2];
    RB[3] = temp[3];
}
void Processor::DI(DByte z)
{
    Print("F:");
    Print("DI");
    Print(z);
    Print();

    DWORD tempA = MAKELONG(MAKEWORD(RA[3], RA[2]), MAKEWORD(RA[1], RA[0]));
    WORD tempZ = MAKEWORD(toHex(z[1]), toHex(z[0]));

    DWORD resultInt = tempA / tempZ;

    DWORD resultRemainder = tempA % tempZ;

    RA = DWORDtoWord(resultInt);

    RB = DWORDtoWord(resultRemainder);

    Print("Result: RA ");
    Print(toChar(RA));
    Print( "RB ");
    Print(toChar(RB));
    Print();

    Print();
}
void Processor::CMPA(void)
{
    Print("F:");
    Print("CMPA");
    Print();

    DWORD tempA = MAKELONG(MAKEWORD(RA[3], RA[2]), MAKEWORD(RA[1], RA[0]));

    DWORD tempB = MAKELONG(MAKEWORD(RB[3], RB[2]), MAKEWORD(RB[1], RB[0]));

    if(tempA < tempB)
    {
        SF = 2;
    }
    else if(tempA == tempB)
    {
        SF = 0;
    }
    else
    {
        SF = 1;
    }
}
void Processor::JP(DByte q)
{
    Print("F:");
    Print("JP");
    Print(q);
    Print();
    PS = toHex(q);
}
void Processor::JE(DByte q)
{
    Print("F:");
    Print("JE");
    Print(q);
    Print();
    if(SF == 0)
    {
        PS = toHex(q);
    }
}
void Processor::JG(DByte q)
{
    Print("F:");
    Print("JG");
    Print(q);
    Print();
    if(SF == 1)
    {
        PS = toHex(q);
    }
}
void Processor::JL(DByte q)
{
    Print("F:");
    Print("JL");
    Print(q);
    Print();
    if(SF == 2)
    {
        PS = toHex(q);
    }
}
void Processor::READ(Word command)
{
    Print("F:");
    Print("READ");
    Print();

    MODE = 0x01;
    IO = command;
}
void Processor::WRIT(Word command)
{
    Print("F:");
    Print("WRIT");
    Print();

    MODE = 0x01;
    IO = command;
}
void Processor::RDM(Word command)
{
    Print("F:");
    Print("RDM");
    Print();

    MODE = 0x01;
    IO = command;
    IO[3] = toHex(IO[3]);
}
void Processor::WTM(Word command)
{
    Print("F:");
    Print("WTM");
    Print();

    MODE = 0x01;
    IO = command;
    IO[3] = toHex(IO[3]);
}
